package top.lyjwn.todo.vcode;

import cn.hutool.core.codec.Base64;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smartboot.http.common.utils.StringUtils;
import top.lyjwn.todo.redis.RedisMap;
import top.lyjwn.todo.template.R;
import top.lyjwn.todo.template.RData;
import top.lyjwn.todo.unique.UIDUtil;
import top.lyjwn.todo.vcode.template.VCodeTemplate;
import top.lyjwn.todo.vcode.utils.VerifyCodeUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

@Component
public class VCode {

    @Inject
    private RedisMap redisMap;

    private final int EXPIRES_TIME = 120;


    private final Logger log = LoggerFactory.getLogger("error");


    /**
     * 验证->验证码
     *
     * @param uuid
     * @param vcode
     * @return
     */
    public RData<VCodeTemplate> verifyVCode(String uuid, String vcode) {
        return verifyVCode(null, null, uuid, vcode);
    }


    /**
     * 验证->验证码
     *
     * @param module
     * @param uuid
     * @param vcode
     * @return
     */
    public RData<VCodeTemplate> verifyVCode(String module, String uuid, String vcode) {
        return verifyVCode(module, null, uuid, vcode);
    }

    /**
     * 验证->验证码
     *
     * @param module 功能模块
     * @param userId 用户id
     * @param uuid   验证码标识符
     * @return
     */
    public RData<VCodeTemplate> verifyVCode(String module, String userId, String uuid, String vcode) {
        String key = builderKey(module, userId, uuid);
        // 查询验证码
        String code = getCodeVal(key);
        // 清除验证码
        delVCode(key);
        if (StringUtils.isBlank(code)) {
            return RData.init(VCodeTemplate.class).error(500, "验证码已过期");
        }
        if (StringUtils.isBlank(vcode) || !vcode.equalsIgnoreCase(code)) {
            return RData.init(VCodeTemplate.class).error(500, "验证码错误");
        }
        return RData.init(VCodeTemplate.class).ok("验证码通过");
    }

    /**
     * 生成验证码
     *
     * @return
     */
    public R generateVCode() {
        return generateVCode(null, null);
    }

    /**
     * 生成验证码
     *
     * @param module 功能模块
     * @return
     */
    public R generateVCode(String module) {
        return generateVCode(module, null);
    }

    /**
     * 生成验证码
     *
     * @param module 功能模块
     * @param userId 用户id
     * @return
     */
    public R generateVCode(String module, String userId) {
        // 生成随机字串
        String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
        String uuid = UIDUtil.getUUID();
        if (module != null && userId != null) {
            saveVCode(module, userId, uuid, verifyCode);
        } else if (module != null && userId == null) {
            saveVCode(module, uuid, verifyCode);
        } else {
            saveVCode(uuid, verifyCode);
        }
        // 生成图片
        int w = 111, h = 36;
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        // 结果模板
        RData<VCodeTemplate> dtoObject;
        try {
            VerifyCodeUtils.outputImage(w, h, stream, verifyCode);
            dtoObject = RData.init().ok("获取成功");
            dtoObject.setData(new VCodeTemplate(Base64.encode(stream.toByteArray()), uuid));
            return dtoObject;
        } catch (Exception e) {
//			e.printStackTrace();
            return R.init().error(500, "生成验证码失败:" + e.getMessage());
        } finally {
            try {
                stream.close();
            } catch (IOException e) {
                log.error("验证码，断开生成图片流失败 " + e.getMessage(), e);
            }
        }
    }

    /**
     * 删除验证码
     *
     * @param key
     */
    private void delVCode(String key) {
        redisMap.delete(key);
    }

    /**
     * 获得验证码
     *
     * @param key
     */
    private String getCodeVal(String key) {
        String o = redisMap.get(key);
        return o;
    }


    /**
     * 保存验证码
     *
     * @param uuid
     * @param vcode
     */
    private void saveVCode(String uuid, String vcode) {
        String key = builderKey(null, null, uuid);
        redisMap.set(key, vcode, EXPIRES_TIME);
    }

    /**
     * 保存验证码
     *
     * @param module 功能模块
     * @param uuid
     * @param vcode
     */
    private void saveVCode(String module, String uuid, String vcode) {
        String key = builderKey(module, null, uuid);
        redisMap.set(key, vcode, EXPIRES_TIME);
    }


    /**
     * 保存验证码
     *
     * @param module 功能模块
     * @param userId 用户id
     * @param uuid
     * @param vcode
     */
    private void saveVCode(String module, String userId, String uuid, String vcode) {
        String key = builderKey(module, userId, uuid);
        redisMap.set(key, vcode, EXPIRES_TIME);
    }


    /**
     * 构造redis键
     *
     * @param module
     * @param userId
     * @param uuid
     * @return
     */
    private String builderKey(String module, String userId, String uuid) {
        StringBuilder key = new StringBuilder("vcode:");
        if (module != null && userId != null) {
            key.append(module).append(":").append(userId).append(":").append(uuid);
        } else if (module != null) {
            key.append(module).append(":").append(uuid);
        } else {
            key.append(":").append(uuid);
        }
        return key.toString();
    }

}
